<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>代理模式（Proxy Pattern）</title>
    <!-- 
  代理模式（Proxy Pattern）是一种结构型设计模式，它为其他对象提供一种代理以控制对该对象的访问。代理模式可以用于多种场景，包括延迟加载、权限控制、日志记录、缓存等。通过代理，客户端可以在不直接接触真实对象的情况下与其交互。

  ### 代理模式的主要组成部分

  1. **主题接口（Subject）**：定义了代理和真实对象的共同接口。
  2. **真实主题（Real Subject）**：实现主题接口的具体对象，代表真实的业务逻辑。
  3. **代理（Proxy）**：持有真实主题的引用，实现主题接口，并在必要时控制对真实主题的访问。

  ### 代理模式的优点

  1. **控制访问**：代理可以在访问真实对象之前进行一些控制，如权限检查、日志记录等。
  2. **延迟加载**：通过代理，可以在需要时才创建真实对象，从而节省资源。
  3. **增强功能**：可以在不修改真实对象的情况下，增强其功能。

  ### 代理模式的缺点

  1. **增加复杂性**：引入代理可能会使系统变得更加复杂，特别是在代理层次较多的情况下。
  2. **性能开销**：由于增加了代理层，可能会引入一些性能开销，尤其是在频繁访问真实对象的场景中。

  ### 示例代码

  以下是一个使用代理模式的简单示例，展示如何通过代理控制对真实对象的访问。

  #### 1. 主题接口（Subject）

  ```javascript
  class Subject {
      request() {
          throw new Error("This method must be implemented.");
      }
  }
  ```

  #### 2. 真实主题（Real Subject）

  ```javascript
  class RealSubject extends Subject {
      request() {
          console.log("真实对象的请求处理");
      }
  }
  ```

  #### 3. 代理（Proxy）

  ```javascript
  class Proxy extends Subject {
      constructor(realSubject) {
          super();
          this.realSubject = realSubject;
      }

      request() {
          // 在访问真实对象之前执行一些操作
          console.log("代理在处理请求之前的操作");

          // 调用真实对象的方法
          this.realSubject.request();

          // 在访问真实对象之后执行一些操作
          console.log("代理在处理请求之后的操作");
      }
  }
  ```

  #### 4. 使用示例

  ```javascript
  const realSubject = new RealSubject();
  const proxy = new Proxy(realSubject);

  proxy.request();
  // 输出:
  // 代理在处理请求之前的操作
  // 真实对象的请求处理
  // 代理在处理请求之后的操作
  ```

  ### 总结

  代理模式是一种灵活且强大的设计模式，适用于需要控制对真实对象访问的场景。通过引入代理，客户端可以在不直接接触真实对象的情况下进行操作，同时实现对真实对象的访问控制和功能增强。在设计系统时，合理运用代理模式可以提高系统的灵活性和可维护性。
  
  --></head>
  <body>
    <script>
      const star = {
        name: "张XX",
        age: 25,
        phone: "13910733521",
      };

      const agent = new Proxy(star, {
        get: function (target, key) {
          if (key === "phone") {
            // 返回经纪人自己的手机号
            return "18611112222";
          }
          if (key === "price") {
            // 明星不报价，经纪人报价
            return 120000;
          }
          return target[key];
        },
        set: function (target, key, val) {
          if (key === "customPrice") {
            if (val < 100000) {
              // 最低 10w
              throw new Error("价格太低");
            } else {
              target[key] = val;
              return true;
            }
          }
        },
      });

      console.log(agent.name); // 输出: 张XX
      console.log(agent.phone); // 输出: 18611112222
      console.log(agent.price); // 输出: 120000

      agent.customPrice = 150000; // 设置自定义价格
      console.log(agent.customPrice); // 输出: 150000
      agent.customPrice = 90000; // 抛出错误: 价格太低
    </script>
  </body>
</html>
